import { ButtonPushAfterEvent, Player, Vector3, world } from "@minecraft/server";
import { Game, GameComponent } from "@sapi-game/main";
import { Duration } from "@sapi-game/utils";
import { CommonForm, formManager } from "sapi-pro";
import { EleDirection, Elevator } from "./elevator";
import { eleMainState } from "../state";

/**电梯主控 */
export class ElevatorController extends GameComponent<eleMainState> {
    get eleList() {
        return this.state.eleList;
    }

    get floorHeight() {
        return this.context.FloorHeight;
    }

    override onAttach(): void {
        this.subscribe(
            Game.events.interval,
            () => {
                this.eleList.forEach((e) => e.tick());
            },
            Duration.fromSeconds(1)
        );
        this.subscribe(world.afterEvents.buttonPush, this.onButtonPush.bind(this));
    }

    onButtonPush(t: ButtonPushAfterEvent) {
        const loc = t.block.location;
        if (!(t.source instanceof Player)) return;
        for (const ele of this.eleList) {
            if (isEqualOnXZ(ele.baseLoc, loc)) {
                this.innerCall(ele, t.source);
                return;
            }
            if (isEqualOnXZ(ele.callButtonLoc, loc)) {
                this.outerCall(ele, loc.y);
                return;
            }
            if (isEqualOnXZ(ele.opeButtonLoc, loc)) {
                this.innerOpe(ele, loc.y);
                return;
            }
        }
    }

    /**外部呼叫 */
    outerCall(elevator: Elevator, y: number) {
        const floor = this.context.utils.calcFloor(y);
        const isDown = (y - elevator.baseLoc.y) % this.floorHeight === 0;
        elevator.call(floor, isDown ? EleDirection.Down : EleDirection.Up);
    }

    /**内部操作按钮 */
    innerOpe(elevator: Elevator, y: number) {
        const isClose = (y - elevator.baseLoc.y) % this.floorHeight === 0;
        if (isClose) {
            elevator.innerClose();
        } else {
            elevator.innerOpen();
        }
    }

    /**内部选层 */
    innerCall(elevator: Elevator, player: Player) {
        formManager.open(player, chooseFloorForm, { elevator: elevator });
    }
}

function isEqualOnXZ(v1: Vector3, v2: Vector3) {
    return v1.x === v2.x && v1.z === v2.z;
}

/**选层表单 */
const chooseFloorForm = CommonForm.ButtonListForm({
    title: "选择楼层",
    generator(form, player, arg) {
        const elevator = arg.elevator as Elevator;
        const goList = elevator.getGoList();
        for (let i = 1; i <= elevator.config.maxFloor; i++) {
            const selected = goList.includes(i);
            form.button(`${selected ? "§a" : ""}第${i}层`);
        }
    },
    handler(selection, ctx) {
        const elevator = ctx.args.elevator as Elevator;
        const floor = selection + 1;
        if (elevator.getGoList().includes(floor)) {
            elevator.removeGo(floor);
        } else {
            elevator.innerGo(floor);
        }
    },
});
